#include <memory>
#include <sys/poll.h>
#include "socket.hpp"

class src_fds{//辅助文件描述符集
public:
    src_fds():_max_fd(1024){}
    int set(int fd,short option){//设置文件描述符集的fd和事件
        if(fd<_max_fd){//检查合法性
            _fds[fd].fd=fd;
            _fds[fd].events=option;
            return fd;
        }
        LOG(WARRING)<<"add repite fd";
        return -1;
    }
    int remove(int fd){//删除文件描述符集的fd
        if(fd<_max_fd&&_fds[fd].fd!=-1){
            _fds[fd].fd=-1;
            return fd;
        }
        LOG(WARRING)<<"remove a no excist fd";
        return -1;
    }
    bool cheackfdIN(int fd){
        if(_fds[fd].fd==-1) return false;
        return _fds[fd].revents&POLLIN==POLLIN;
    }//检查文件描述符的读事件是否就绪
    bool cheackfdOUT(int fd){
        if(_fds[fd].fd==-1) return false;
        return _fds[fd].revents&POLLOUT==POLLOUT;
    }//检查文件描述符的写事件是否就绪
    int max_fd(){ return _max_fd;}
    void clear(){//清除辅助文件描述符集
        for(int i=0;i<_max_fd;i++){
            _fds[i].fd=-1;
        }
    }
    struct pollfd* fds() {return _fds;}
private:
    struct pollfd _fds[1024];
    const int _max_fd;
};

class server{
public:
    server(uint16_t port):_port(port){
    }
    void init(){
        _listenfd=std::make_unique<TcpSocket>(_port);
        _isrunning=true;
        _listenfd->BulitTcpSocket(_port);
        _rfds.set(_listenfd->Fd(),POLLIN);
    }
    void start(){
        while(_isrunning){
            int n=poll(_rfds.fds(),_rfds.max_fd(),-1);
            switch (n)
            {
            case 0:
                LOG(INFO)<<"no I/O aready";//没有I/O事件发生
                break;
            case -1:
                LOG(ERROR)<<"select error:"<<strerror(errno);
                break;
            default:
                //处理I/O事件
                handle_rfds();
                break;
            }
        }
    }
private:
    void handle_rfds(){
        //1.处理listen_socket
        if(_rfds.cheackfdIN(_listenfd->Fd())){//读取监听到的链接
            inetaddr client;
            int newfd=_listenfd->accept(&client);
            LOG(INFO)<<"新增用户:"<<client.addr();
            _rfds.set(newfd,POLLIN);
        }
        //2.处理其他socket
        for(int i=0;i<_rfds.max_fd();i++){
            if(i==_listenfd->Fd()) continue;
            if(_rfds.cheackfdIN(i)){//i对应的fd收到了数据，对该数据读取并处理
                char in_buffer[2048];
                int n=recv(i,in_buffer,sizeof(in_buffer),0);
                if(n==0){
                    LOG(INFO)<<"client :"<<i<<" 断开了链接";
                    close(i);
                    _rfds.remove(i);
                }
                else if(n>0){
                    in_buffer[n]='\0';
                    std::cout<<"client["<<i<<"] say#"<<in_buffer<<std::endl;
                    std::string recv_mesg="echo#";
                    recv_mesg+=in_buffer;
                    send(i,recv_mesg.c_str(),recv_mesg.size(),0);
                }
                if(n==-1){
                    LOG(ERROR)<<"fd :"<<i<<"is error"<<strerror(errno);
                }
            }
        }
    }
    std::unique_ptr<Socket> _listenfd;
    uint16_t _port;
    src_fds _rfds;//只读属性的fds
    bool _isrunning;
};